import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { TreeRepository } from 'typeorm';
import { Menu } from './entities/menu.entity';
import { CreateMenuDto } from './dto/create-menu.dto';
import { BusinessException, formatTime } from '@/common';
import { UpdateMenuDto } from './dto/update-menu.dto';
import { RoleService } from '../role/role.service';
import { Role } from '../role/entities/role.entity';
import { menuQueryVo } from '@/common/interface';

@Injectable()
export class MenuService {
  constructor(
    @InjectRepository(Menu)
    private readonly menuRepository: TreeRepository<Menu>,
    private readonly roleService: RoleService
  ) {}

  async findMenuTree(params: menuQueryVo) {
    const list = await this.menuRepository.findTrees(); // 使用findTrees()获取所有树形结构

    return list;
  }

  async create(createMenuDto: CreateMenuDto) {
    const menu = new Menu();
    [
      'type',
      'name',
      'icon',
      'mark',
      'componentName',
      'routePath',
      'componentPath',
      'order',
      'display',
      'style'
    ].forEach((v) => {
      if (createMenuDto[v]) {
        menu[v] = createMenuDto[v];
      }
    });
    // 如果有父级参数
    if (createMenuDto?.parent) {
      const parent = new Menu();
      parent.id = createMenuDto.parent;
      menu.parent = parent;
      // 重制 componentPath; 如果父级菜单和当前添加菜单都是目录，则componentPath为Layout
      const menuOne = await this.findOne(createMenuDto.parent);
      menu.componentPath =
        createMenuDto.type == 0 && menuOne.type === 0
          ? 'Layout'
          : createMenuDto.componentPath;
    }
    return this.menuRepository.save(menu);
  }

  async update(updateMenuDto: UpdateMenuDto) {
    // 菜单
    const menu = new Menu();
    [
      'id',
      'type',
      'name',
      'icon',
      'mark',
      'componentName',
      'routePath',
      'componentPath',
      'order',
      'display',
      'style'
    ].forEach((v) => {
      if (updateMenuDto[v]) {
        menu[v] = updateMenuDto[v];
      }
    });

    // 父级
    if (updateMenuDto.parent) {
      const parent = new Menu();
      parent.id = updateMenuDto.parent;
      menu.parent = parent;

      // 重制 componentPath; 如果父级菜单和当前添加菜单都是目录，则componentPath为Layout
      const menuOne = await this.findOne(updateMenuDto.parent);
      menu.componentPath =
        updateMenuDto.type == 0 && menuOne.type === 0
          ? 'Layout'
          : updateMenuDto.componentPath;
    }

    return this.menuRepository.save(menu);
  }

  findOne(id: number) {
    return this.menuRepository.findOne({
      where: { id },
      relations: ['parent', 'children']
    });
  }

  async remove(id: number) {
    const menu = await this.findOne(id);
    if (menu?.children?.length > 0) {
      throw new BusinessException({
        code: 400,
        message: '该菜单有下级菜单，不能删除'
      });
    }

    return this.menuRepository.remove(menu);
  }

  async findPermissionMenuTree(roles: Role[], isAdmin: number = 0) {
    // 获取所有菜单
    const menus = await this.menuRepository.findTrees();
    let list = [];

    // 是否超级管理员 - 超级管理员拥有所有权限
    if (isAdmin) {
      list = menus;
    } else {
      // 获取用户的所有角色，并根据角色关联的菜单进行处理
      const roleIds = roles.map(({ id }) => id);

      const userRoles = await this.roleService.findByIds(roleIds);

      const roleMenus: Menu[] = userRoles.reduce((total, current) => {
        total.push(...current.menus);
        return total;
      }, []);
      const permissions = roleMenus.map(({ mark }) => mark);
      list = this.formatTree(menus, permissions);
    }

    return list;
  }

  formatTree(menus: any, permissions: any) {
    return menus.filter((v) => {
      const hasPermission = permissions.includes(v.mark);

      if (v.children) {
        v.children = this.formatTree(v.children, permissions);
      }

      return hasPermission;
    });
  }

  changeDisplay(id: number, display: number) {
    return this.menuRepository.update(id, { display });
  }

  setQuickMenu(id: number, quickMenu: number) {
    return this.menuRepository.update(id, { quickMenu });
  }
}
